Entity = class()

function Entity:init()
    self.x,self.y,self.z = 0,0,0
    self.xd,self.yd,self.zd = 0,0,0
    self.xo,self.yo,self.zo = 0,0,0
    self.xdo,self.ydo,self.zdo = 0,0,0
    self.xRot,self.yRot = 0,0
    self.onGround = false
    self.removed = false
end

function Entity:setSize(width,height)
    self.width = width
    self.height = height
    self.heightOffset = height / 2
    -- self:resetPos()
end

function Entity:setPos(x,y,z)
    self.x,self.y,self.z = x,y,z
    local w,h = self.width / 2,self.height / 2
    self.aabb = AABB(x - w,y - h,z - w,x + w,y + h,z + w)
end

function Entity:tick()
    self.xo = self.x
    self.yo = self.y
    self.zo = self.z
end

function Entity:moveRelative(xa,za,speed)
    local dist = xa * xa + za * za
    if dist < 0.01 then return end
    
    dist = speed / math.sqrt(dist)
    xa = xa * dist
    za = za * dist
    
    local sin = math.sin(self.yRot * math.pi / 180.0)
    local cos = math.cos(self.yRot * math.pi / 180.0)
    
    self.xd = self.xd + xa * cos - za * sin
    self.zd = self.zd + za * cos + xa * sin
end

function Entity:move(xa,ya,za)
    local xaOrg = xa
    local yaOrg = ya
    local zaOrg = za
    
    local xo,zo = self.x,self.z
    
    local aabbs = world:getCubesWithInAABB(self.aabb:expend(xa,ya,za))
    
    for k,aabb in pairs(aabbs) do
        ya = aabb:clipYcollide(self.aabb,ya)
    end
    
    self.aabb:move(0,ya,0)
    
    for k,aabb in pairs(aabbs) do
        xa = aabb:clipXcollide(self.aabb,xa)
    end
    self.aabb:move(xa,0,0)
    
    for k,aabb in pairs(aabbs) do
        za = aabb:clipZcollide(self.aabb,za)
    end
    self.aabb:move(0,0,za)
    
    self.horizontalCollision = (xaOrg ~= xa) or (zaOrg ~= za)
    self.verticalCollision = yaOrg ~= ya
    self.onGround = self.verticalCollision and (yaOrg < 0.0)
    
    self.xdo,self.ydo,self.zdo = self.xd,self.yd,self.zd
    
    if xaOrg ~= xa then self.xd = 0.0 end
    if yaOrg ~= ya then self.yd = 0.0 end
    if zaOrg ~= za then self.zd = 0.0 end
    
    self.x = (self.aabb.x0 + self.aabb.x1) / 2.0
    self.y = self.aabb.y0 + self.heightOffset
    self.z = (self.aabb.z0 + self.aabb.z1) / 2.0
end

function Entity:isInWater()
    return world:containLiquid(self.aabb:grow(0,-0.4,0),Block.water.id)
end

function Entity:isInLava()
    return world:containLiquid(self.aabb:grow(0,-0.1,0),Block.lava.id)
end

function Entity:isFree(xa,ya,za)
    local box = self.aabb:cloneMove(xa,ya,za)
    aabbs = world:getCubesWithInAABB(box)
    if #aabbs > 0 then
        return false
    end
    if world:containAnyLiquid(box) then
        return false
    end
    return true
end

function Entity:getPosVec3()
    return vec3(self.x,self.y,self.z)
end

function Entity:getPos()
    return {x = self.x,y = self.y,z = self.z}
end

function Entity:distanceToSqr(pos)
    local xa = self.x - pos.x
    local ya = self.y - pos.y
    local za = self.z - pos.z
    return xa * xa + ya * za + za * za
end

function Entity:getBrightness(x,y,z)
    x,y,z = math.floor(x),math.floor(y),math.floor(z)
    return (1 - GameSetting.Brightness) * world:getBrightness(x,y,z) / Brightness.Max + GameSetting.Brightness
end
